package com.commons.dao;

import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;

import com.cache.simplecache.SimpleCacheManager;
import com.commons.page.PageHolder;
import com.commons.sql.List2Map;
import com.commons.sql.SearchCondition;
import com.commons.sql.SqlCountUtil;
import com.commons.sql.SqlUtil;
import com.commons.utils.ReflectionUtils;


public class DaoBase<T> {

	
	protected Class entityClass;
	
	private SimpleCacheManager simpleCacheManager;
	
	private String generateSQL(int type,List<SearchCondition> params)
	{
		String sql="";
	
		String key=""+entityClass.hashCode()+type+(params==null?"":params.hashCode());
		sql=(String)simpleCacheManager.getCache(key);
		
		if(StringUtils.isEmpty(sql))
		{
			switch (type) {
			case SqlUtil.INSERT:sql=SqlUtil.generateInsertSql(entityClass);break;
			case SqlUtil.REPLACE:sql=SqlUtil.generateReplaceSql(entityClass);break;
			case SqlUtil.DELETE:sql=SqlUtil.generateDeleteSql(entityClass,params);break;
			case SqlUtil.DELETE_ID:sql=SqlUtil.generateDeleteSqlById(entityClass);break;
			case SqlUtil.SELECT:sql=SqlUtil.generateSelectSql(entityClass,params);break;
			case SqlUtil.SELECT_ID:sql=SqlUtil.generateSelectSqlById(entityClass);break;
			default:
			break;
		}
			simpleCacheManager.addCache(key, sql);
		}
		return sql;
	}
	
	private String generateSQL(int type)
	{
		return generateSQL(type,null);
	}

	public void setEntityClass(Class entityClass) {
		this.entityClass = entityClass;
	}

	private SimpleJdbcTemplate jdbc;

	public void setJdbc(SimpleJdbcTemplate jdbc) {
		this.jdbc = jdbc;
	}
	
	public DaoBase()
	{	
		this.entityClass = ReflectionUtils.getSuperClassGenricType(getClass());
	}

	public int insert(T t)
	{
		SqlParameterSource paramSource=new BeanPropertySqlParameterSource(t);
		String sql=generateSQL(SqlUtil.INSERT);
		GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();
		jdbc.getNamedParameterJdbcOperations().update(sql, paramSource,keyHolder);
		return keyHolder.getKey().intValue();
	}
	
	public int replace(T t)
	{
		SqlParameterSource paramSource=new BeanPropertySqlParameterSource(t);
		String sql=generateSQL(SqlUtil.REPLACE);
		return jdbc.update(sql, paramSource);
		
	}
	
	public int delete(T t,List<SearchCondition> params)
	{
		String sql=generateSQL(SqlUtil.DELETE, params);
		return jdbc.update(sql, params);
	}
	
	public int deleteById(int id)
	{
		String sql=generateSQL(SqlUtil.DELETE_ID);
		return jdbc.update(sql, id);
	}
	
	public List<T> select(List<SearchCondition> params)
	{
		String sql=generateSQL(SqlUtil.SELECT,params);
		RowMapper<T> rm=new BeanPropertyRowMapper<T>(entityClass);
		return jdbc.query(sql, rm, List2Map.execute(params));
	}
	
	public void  select(PageHolder<T> pageHolder, List<SearchCondition> params,String orderBy,String groupBy)
	{
		String sql=generateSQL(SqlUtil.SELECT,params);
		
		String countSql=SqlCountUtil.getCountSql(sql);
		int count=getCount(countSql);
		pageHolder.setRowCount(count);
		
		if(StringUtils.isNotEmpty(groupBy))
		{
			sql+=" group by "+groupBy;
		}
		if(StringUtils.isNotEmpty(orderBy))
		{
			sql+=" order by "+orderBy;
		}
		sql+=" limit "+pageHolder.getRowOffset()+","+pageHolder.getPageSize();
		
		RowMapper<T> rm=new BeanPropertyRowMapper<T>(entityClass);
		List<T> result= jdbc.query(sql, rm, List2Map.execute(params));
		
		pageHolder.setList(result);
		
	}
	
	public int getCount(String sql)
	{
		return jdbc.queryForInt(sql);
	}
	
	
	public <T> T selectById(long id)
	{
		try
		{
			String sql=generateSQL(SqlUtil.SELECT_ID);
			RowMapper<T> rm = (RowMapper<T>) ParameterizedBeanPropertyRowMapper.newInstance(entityClass);  
			return (T) jdbc.queryForObject(sql, rm, id);
		}catch (EmptyResultDataAccessException e) {
			return null;
		}
	}


	public void setSimpleCacheManager(SimpleCacheManager simpleCacheManager) {
		this.simpleCacheManager = simpleCacheManager;
	}
	
	public Class getEntityClass() {
		return entityClass;
	}
	
}
